{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1>Real-Time SMA Crossover Strategy</h1>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import fxcmpy\n",
    "import time\n",
    "import datetime as dt\n",
    "from pyti.simple_moving_average import simple_moving_average as sma"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>User and Strategy Parameters</h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "token = 'YOUR_TOKEN_HERE'\n",
    "\n",
    "symbol = 'EUR/USD'\n",
    "\n",
    "# Available periods : 'm1', 'm5', 'm15', 'm30', 'H1', 'H2', 'H3', 'H4', 'H6', 'H8','D1', 'W1', or 'M1'.\n",
    "timeframe = \"m1\" \n",
    "\n",
    "fast_sma_periods = 10\n",
    "slow_sma_periods = 30\n",
    "\n",
    "amount = 3\n",
    "stop = -10\n",
    "limit = 30\n",
    "\n",
    "# Global Variables\n",
    "pricedata = None\n",
    "numberofcandles = 300"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Connecting to FXCM</h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "con = fxcmpy.fxcmpy(access_token=token, log_level=\"error\", log_file=None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Getting Historical Data</h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# This function runs once at the beginning of the strategy to create price/indicator streams\n",
    "\n",
    "def Prepare():\n",
    "    global pricedata\n",
    "    \n",
    "    print(\"Requesting Initial Price Data...\")\n",
    "    pricedata = con.get_candles(symbol, period=timeframe, number=numberofcandles)\n",
    "    print(pricedata)\n",
    "    print(\"Initial Price Data Received...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Strategy Control</h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Get latest close bar prices and run Update() every close of bar per timeframe parameter\n",
    "\n",
    "def StrategyHeartBeat():\n",
    "    while True:\n",
    "        currenttime = dt.datetime.now()\n",
    "        if timeframe == \"m1\" and currenttime.second == 0 and getLatestPriceData():\n",
    "            Update()\n",
    "        elif timeframe == \"m5\" and currenttime.second == 0 and currenttime.minute % 5 == 0 and getLatestPriceData(): \n",
    "            Update()\n",
    "            time.sleep(240)\n",
    "        elif timeframe == \"m15\" and currenttime.second == 0 and currenttime.minute % 15 == 0 and getLatestPriceData(): \n",
    "            Update()\n",
    "            time.sleep(840)\n",
    "        elif timeframe == \"m30\" and currenttime.second == 0 and currenttime.minute % 30 == 0 and getLatestPriceData():\n",
    "            Update()\n",
    "            time.sleep(1740)\n",
    "        elif currenttime.second == 0 and currenttime.minute == 0 and getLatestPriceData():\n",
    "            Update()\n",
    "            time.sleep(3540)\n",
    "        time.sleep(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Returns True when pricedata is properly updated\n",
    "\n",
    "def getLatestPriceData():\n",
    "    global pricedata\n",
    "\n",
    "    # Normal operation will update pricedata on first attempt\n",
    "    new_pricedata = con.get_candles(symbol, period=timeframe, number=numberofcandles)\n",
    "    if new_pricedata.index.values[len(new_pricedata.index.values)-1] != pricedata.index.values[len(pricedata.index.values)-1]:\n",
    "        pricedata = new_pricedata\n",
    "        return True\n",
    "   \n",
    "    # If data is not available on first attempt, try up to 3 times to update pricedata    \n",
    "    counter = 0 \n",
    "    while new_pricedata.index.values[len(new_pricedata.index.values)-1] == pricedata.index.values[len(pricedata.index.values)-1] and counter < 3:\n",
    "        print(\"No updated prices found, trying again in 10 seconds...\")\n",
    "        counter+=1\n",
    "        time.sleep(10)\n",
    "        new_pricedata = con.get_candles(symbol, period=timeframe, number=numberofcandles)\n",
    "    if new_pricedata.index.values[len(new_pricedata.index.values)-1] != pricedata.index.values[len(pricedata.index.values)-1]:\n",
    "        pricedata = new_pricedata\n",
    "        return True\n",
    "    else:\n",
    "        return False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Strategy Logic</h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# This function is run every time a candle closes\n",
    "\n",
    "def Update():\n",
    "    print(str(dt.datetime.now()) + \" \" + timeframe + \" Bar Closed - Running Update Function...\")\n",
    "\n",
    "    # Calculate Indicators\n",
    "    iFastSMA = sma(pricedata['bidclose'], fast_sma_periods)\n",
    "    iSlowSMA = sma(pricedata['bidclose'], slow_sma_periods)\n",
    "\n",
    "    # Print Price/Indicators\n",
    "    print(\"Close Price: \" + str(pricedata['bidclose'][len(pricedata)-1]))\n",
    "    print(\"Fast SMA: \" + str(iFastSMA[len(iFastSMA)-1]))\n",
    "    print(\"Slow SMA: \" + str(iSlowSMA[len(iSlowSMA)-1]))\n",
    "\n",
    "    # TRADING LOGIC\n",
    "    if crossesOver(iFastSMA,iSlowSMA):\n",
    "        print(\"\t  BUY SIGNAL!\")\n",
    "        if countOpenTrades(\"S\") > 0:\n",
    "            print(\"\t  Closing Sell Trade(s)...\")\n",
    "            exit(\"S\")\n",
    "        print(\"\t  Opening Buy Trade...\")\n",
    "        enter(\"B\")\n",
    "    \n",
    "    if crossesUnder(iFastSMA,iSlowSMA):\n",
    "        print(\"\t  SELL SIGNAL!\")\n",
    "        if countOpenTrades(\"B\") > 0:\n",
    "            print(\"\t  Closing Buy Trade(s)...\")\n",
    "            exit(\"B\")\n",
    "        print(\"\t  Opening Sell Trade...\")\n",
    "        enter(\"S\")\n",
    "    print(str(dt.datetime.now()) + \" \" + timeframe + \" Update Function Completed.\\n\")\n",
    "    print(\"\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Returns true if stream1 crossed over stream2 in most recent candle, stream2 can be integer/float or data array\n",
    "\n",
    "def crossesOver(stream1, stream2):\n",
    "    if isinstance(stream2, int) or isinstance(stream2, float):\n",
    "        if stream1[len(stream1)-1] <= stream2:\n",
    "            return False\n",
    "        else:\n",
    "            if stream1[len(stream1)-2] > stream2:\n",
    "                return False\n",
    "            elif stream1[len(stream1)-2] < stream2:\n",
    "                return True\n",
    "            else:\n",
    "                x = 2\n",
    "                while stream1[len(stream1)-x] == stream2:\n",
    "                    x = x + 1\n",
    "                if stream1[len(stream1)-x] < stream2:\n",
    "                    return True\n",
    "                else:\n",
    "                    return False\n",
    "    else:\n",
    "        if stream1[len(stream1)-1] <= stream2[len(stream2)-1]:\n",
    "            return False\n",
    "        else:\n",
    "            if stream1[len(stream1)-2] > stream2[len(stream2)-2]:\n",
    "                return False\n",
    "            elif stream1[len(stream1)-2] < stream2[len(stream2)-2]:\n",
    "                return True\n",
    "            else:\n",
    "                x = 2\n",
    "                while stream1[len(stream1)-x] == stream2[len(stream2)-x]:\n",
    "                    x = x + 1\n",
    "                if stream1[len(stream1)-x] < stream2[len(stream2)-x]:\n",
    "                    return True\n",
    "                else:\n",
    "                    return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Returns true if stream1 crossed under stream2 in most recent candle, stream2 can be integer/float or data array\n",
    "\n",
    "def crossesUnder(stream1, stream2):\n",
    "    if isinstance(stream2, int) or isinstance(stream2, float):\n",
    "        if stream1[len(stream1)-1] >= stream2:\n",
    "            return False\n",
    "        else:\n",
    "            if stream1[len(stream1)-2] < stream2:\n",
    "                return False\n",
    "            elif stream1[len(stream1)-2] > stream2:\n",
    "                return True\n",
    "            else:\n",
    "                x = 2\n",
    "                while stream1[len(stream1)-x] == stream2:\n",
    "                    x = x + 1\n",
    "                if stream1[len(stream1)-x] > stream2:\n",
    "                    return True\n",
    "                else:\n",
    "                    return False\n",
    "    else:\n",
    "        if stream1[len(stream1)-1] >= stream2[len(stream2)-1]:\n",
    "            return False\n",
    "        else:\n",
    "            if stream1[len(stream1)-2] < stream2[len(stream2)-2]:\n",
    "                return False\n",
    "            elif stream1[len(stream1)-2] > stream2[len(stream2)-2]:\n",
    "                return True\n",
    "            else:\n",
    "                x = 2\n",
    "                while stream1[len(stream1)-x] == stream2[len(stream2)-x]:\n",
    "                    x = x + 1\n",
    "                if stream1[len(stream1)-x] > stream2[len(stream2)-x]:\n",
    "                    return True\n",
    "                else:\n",
    "                    return False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Order Management</h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# This function places a market order in the direction BuySell, \"B\" = Buy, \"S\" = Sell, uses symbol, amount, stop, limit\n",
    "\n",
    "def enter(BuySell):\n",
    "    direction = True;\n",
    "    if BuySell == \"S\":\n",
    "        direction = False;\n",
    "    try:\n",
    "        opentrade = con.open_trade(symbol=symbol, is_buy=direction,amount=amount, time_in_force='GTC',order_type='AtMarket',is_in_pips=True,limit=limit, stop=stop)\n",
    "    except:\n",
    "        print(\"\t  Error Opening Trade.\")\n",
    "    else:\n",
    "        print(\"\t  Trade Opened Successfully.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# This function closes all positions that are in the direction BuySell, \"B\" = Close All Buy Positions, \n",
    "# \"S\" = Close All Sell Positions, uses symbol\n",
    "\n",
    "def exit(BuySell=None):\n",
    "    openpositions = con.get_open_positions(kind='list')\n",
    "    isbuy = True\n",
    "    if BuySell == \"S\":\n",
    "        isbuy = False\n",
    "    for position in openpositions:\n",
    "        if position['currency'] == symbol:\n",
    "            if BuySell is None or position['isBuy'] == isbuy:\n",
    "                print(\"\t  Closing tradeID: \" + position['tradeId'])\n",
    "                try:\n",
    "                    closetrade = con.close_trade(trade_id=position['tradeId'], amount=position['amountK'])\n",
    "                except:\n",
    "                    print(\"\t  Error Closing Trade.\")\n",
    "                else:\n",
    "                    print(\"\t  Trade Closed Successfully.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Returns number of Open Positions for symbol in the direction BuySell, returns total number of both Buy and Sell positions if no direction is specified\n",
    "\n",
    "def countOpenTrades(BuySell=None):\n",
    "    openpositions = con.get_open_positions(kind='list')\n",
    "    isbuy = True\n",
    "    counter = 0\n",
    "    if BuySell == \"S\":\n",
    "        isbuy = False\n",
    "    for position in openpositions:\n",
    "        if position['currency'] == symbol:\n",
    "            if BuySell is None or position['isBuy'] == isbuy:\n",
    "                counter+=1\n",
    "    return counter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Running The Strategy</h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Prepare() # Initialize strategy\n",
    "StrategyHeartBeat() # Run strategy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
